/******************************************************************************
 * Copyright (C) 2009 Peter ZHOU <peterzhoulei@gmail.com>                     *
 *                                                                            *
 * This program is free software; you can redistribute it and/or              *
 * modify it under the terms of the GNU General Public License as             *
 * published by the Free Software Foundation; either version 2 of             *
 * the License, or (at your option) any later version.                        *
 *                                                                            *
 * This program is distributed in the hope that it will be useful,            *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
 * GNU General Public License for more details.                               *
 *                                                                            *
 * You should have received a copy of the GNU General Public License          *
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.      *
 ******************************************************************************/

#import "ddIM_controller.h"

@implementation ddIM_controller

-(id)init
{
	self = [super init];
	return self;
}

-(BOOL)inputText:(NSString*)string client:(id)sender
{
	[string retain];
	//read dictionary file
	BOOL inputHandled = NO;
	NSScanner* scanner = [NSScanner scannerWithString:string];
	NSCharacterSet* lowerCaseCharset = [NSCharacterSet lowercaseLetterCharacterSet];
	NSString* tmpstr;
	NSInteger searchLocation;
	BOOL isLowerCaseLetter = [scanner scanCharactersFromSet:lowerCaseCharset intoString:&tmpstr];
	extern ddIM_dict* dict;
	extern IMKCandidates* candidates;
	[candidates setDismissesAutomatically:NO];
	if ( [string compare:@"'"] == 0 )
	{
		[self originalBufferAppend:@"'" client:sender];
	}
	else if ( ( [string compare:@" "] == 0 ) && ( [_originalBuffer length] > 0 ) )
	{
		if ( [_candidatesBuffer count] != 0 )
			[self replaceString:[_candidatesBuffer objectAtIndex:currentPage*8]];
		else
		{
			[sender insertText:[currentBuffer lastObject] replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
			[self setComposedBuffer:@""];
			[self setOriginalBuffer:@""];
			[currentBuffer removeAllObjects];
		}
	}
	else if ( ( [string compare:@"."] == 0 ) && ( [_candidatesBuffer count] > 0 ) )
	{
		NSLog(@"page up");
		if ( currentPage < totalPage )
		{
			currentPage++;
		}
		[self showCandidates];
	}
	else if ( ( [string compare:@","] == 0 ) && ( [_candidatesBuffer count] > 0 ) )
	{
		NSLog(@"page down");
		if ( currentPage != 0 )
		{
			currentPage--;
		}
		[self showCandidates];
	}
	else if ( isLowerCaseLetter )
	{
		[self originalBufferAppend:tmpstr client:sender];
//		NSLog([@"lastbuffer:" stringByAppendingString:[currentBuffer lastObject]]);
		NSScanner* scanner2 = [NSScanner scannerWithString:[currentBuffer lastObject]];
		NSLog([currentBuffer lastObject]);
		if ( ![scanner2 scanUpToCharactersFromSet:lowerCaseCharset intoString:NULL] )
		{
			searchLocation = 0;
		}
		else
		{
			searchLocation = [scanner2 scanLocation];
			NSLog([@"location:" stringByAppendingString:[NSString stringWithFormat:@"%d", searchLocation]]);
		}
		NSLog([@"searching:" stringByAppendingString:[[currentBuffer lastObject] substringFromIndex:searchLocation]]);
		NSLog([self prevBuffer]);
		_candidatesBuffer = [dict searchDict:[[currentBuffer lastObject] substringFromIndex:searchLocation]:[self prevBuffer]];
		if ( [_candidatesBuffer count] % 8 == 0 )
			totalPage = [_candidatesBuffer count] / 8;
		else
			totalPage = [_candidatesBuffer count] / 8 + 1;
		totalPage--;
		currentPage = 0;
		[self showCandidates];
	}
	else
		return NO;
	inputHandled = YES;
	return inputHandled;
}

-(void)showCandidates
{
	extern IMKCandidates* candidates;
	[candidates	updateCandidates];
	if ( [_candidatesBuffer count] > 0 )
	{
		[candidates show:kIMKLocateCandidatesBelowHint];
	}
}

- (NSArray*)candidates:(id)sender
{
	_currentClient = sender;
	if ( currentPage == totalPage )
		return [_candidatesBuffer subarrayWithRange:NSMakeRange(currentPage*8, [_candidatesBuffer count] - 8 * totalPage)];
	else
		return [_candidatesBuffer subarrayWithRange:NSMakeRange(currentPage*8, 8)];
}

-(void)commitComposition:(id)sender
{
	extern ddIM_dict* dict;
	NSMutableString* text = [self composedBuffer];
	[self setPrevBuffer:text];
	[sender insertText:text replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
	if ( ( [text length] <=5 ) && ( [text length] >0 ) )
	{
		NSLog([_originalBuffer stringByAppendingString:text]);
		if ( [currentBuffer count] > 1 )
			[dict addDict:[[currentBuffer objectAtIndex:0] substringToIndex:([[currentBuffer objectAtIndex:0] length]-1)]:text];
		else if ( [currentBuffer count] == 1 )
			[dict editDict:[[currentBuffer objectAtIndex:0] substringToIndex:([[currentBuffer objectAtIndex:0] length]-1)]:text];
	}
	[self setComposedBuffer:@""];
	[self setOriginalBuffer:@""];
	[currentBuffer removeAllObjects];
}

-(NSMutableString*)composedBuffer
{
	if ( _composedBuffer == nil )
	{
		_composedBuffer = [[NSMutableString alloc] init];
	}
	return _composedBuffer;
}

-(void)setComposedBuffer:(NSString*)string
{
	NSMutableString* buffer = [self composedBuffer];
	[buffer setString:string];
}

-(NSMutableString*)originalBuffer
{
	if ( _originalBuffer == nil )
	{
		_originalBuffer = [[NSMutableString alloc] init];
	}
	return _originalBuffer;
}

-(void)originalBufferAppend:(NSString*)string client:(id)sender
{
	extern ddIM_dict* dict;
	if ( ( currentBuffer == nil ) || ( [currentBuffer count] == 0) )
	{
		[[self originalBuffer] appendString:string];
		NSMutableString* buffer	= [NSMutableString stringWithString:[self originalBuffer]];
		currentBuffer = [[NSMutableArray alloc] init];
		[currentBuffer addObject:buffer];
	}
	else
	{
		NSRange range = [_originalBuffer rangeOfString:@"'" options:NSBackwardsSearch];
		NSMutableString* lastbuffer;
//		bool addSeperator = false;
		if ( range.location != NSNotFound )
		{
			lastbuffer = [[NSMutableString alloc] init];
			[lastbuffer appendString:[_originalBuffer substringFromIndex:(range.location+1)]];
		}
		else
			lastbuffer = [NSMutableString stringWithString:[self originalBuffer]];
//		if ( [dict isCandidate:lastbuffer] )
//		{
			[lastbuffer appendString:string];
//			if ( ![dict isCandidate:lastbuffer] )
//			{
//				[_originalBuffer appendString:@"'"];
//				addSeperator = true;
//			}
//		}
		[[self originalBuffer] appendString:string];
		for ( NSInteger i = 0; i<[currentBuffer count]; i++)
		{
//			if ( addSeperator )
//				[[currentBuffer objectAtIndex:i] appendString:@"'"];
			[[currentBuffer objectAtIndex:i] appendString:string];
		}
	}
	[self autoPinyinPartition];
	[sender setMarkedText:[currentBuffer lastObject] selectionRange:NSMakeRange(0, [[currentBuffer lastObject] length]) replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
}

-(void)setOriginalBuffer:(NSString*)string
{
	NSMutableString* buffer = [self originalBuffer];
	[buffer setString:string];
}

-(NSMutableString*)prevBuffer
{
	if ( _prevBuffer == nil )
	{
		_prevBuffer = [[NSMutableString alloc] init];
	}
	return _prevBuffer;
}

-(void)setPrevBuffer:(NSMutableString*)string
{
	NSMutableString* buffer = [self prevBuffer];
	[buffer setString:string];
}

-(BOOL)didCommandBySelector:(SEL)aSelector client:(id)sender
{
	if ( [self respondsToSelector:aSelector] )
	{
		NSString* bufferedText = [self originalBuffer];
		
		if ( bufferedText && [bufferedText length] > 0 )
		{
			if ( aSelector == @selector( insertNewline: ) || aSelector == @selector( deleteBackward: ) )
			{
				[self performSelector:aSelector withObject:sender];
				return YES;
			}
		}
	}
	return NO;
}

-(void)insertNewline:(id)sender
{
//	[self setComposedBuffer:@""];
//	[self commitComposition:_currentClient];
//	[self setOriginalBuffer:@""];
}

-(void)deleteBackward:(id)sender
{
	NSInteger i;
	NSInteger searchLocation;
	NSMutableString* str = [NSMutableString stringWithString:[currentBuffer lastObject]];
	NSScanner* scanner = [NSScanner scannerWithString:str];
	NSCharacterSet* lowerCaseCharset = [NSCharacterSet lowercaseLetterCharacterSet];
	extern ddIM_dict* dict;
	[scanner scanUpToCharactersFromSet:lowerCaseCharset intoString:NULL];
	if ( ![scanner isAtEnd] )
	{
		for (i = 0; i<[currentBuffer count]; i++)
		{
			if ( [[currentBuffer objectAtIndex:i] hasSuffix:@"'"] )
				[[currentBuffer objectAtIndex:i] replaceCharactersInRange:NSMakeRange([[currentBuffer objectAtIndex:i] length] - 1, 1) withString:@""];
			[[currentBuffer objectAtIndex:i] replaceCharactersInRange:NSMakeRange([[currentBuffer objectAtIndex:i] length] - 1, 1) withString:@""];
			NSLog([currentBuffer objectAtIndex:i]);
		}
		[self autoPinyinPartition];
		[self setOriginalBuffer:[[self originalBuffer] substringToIndex:([[self originalBuffer] length] - 1)]];
		[sender setMarkedText:[currentBuffer lastObject] selectionRange:NSMakeRange(0, [[currentBuffer lastObject] length]) replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
	}
	else
	{
		for (i = 0; i<[currentBuffer count]; i++)
		{
			[[currentBuffer objectAtIndex:i] replaceCharactersInRange:NSMakeRange([[currentBuffer objectAtIndex:i] length] - 1, 1) withString:@""];
			NSLog([currentBuffer objectAtIndex:i]);
		}
		[currentBuffer removeLastObject];
		[self autoPinyinPartition];
		[sender setMarkedText:[currentBuffer lastObject] selectionRange:NSMakeRange(0, [[currentBuffer lastObject] length]) replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
	}
	NSScanner* scanner2 = [NSScanner scannerWithString:[currentBuffer lastObject]];
	if ( ![scanner2 scanUpToCharactersFromSet:lowerCaseCharset intoString:NULL] )
		searchLocation = 0;
	else
		searchLocation = [scanner2 scanLocation];
	_candidatesBuffer = [dict searchDict:[[currentBuffer lastObject] substringFromIndex:searchLocation]:[self prevBuffer]];
	currentPage = 0;
	[self showCandidates];
}

//- (void)candidateSelectionChanged:(NSAttributedString*)candidateString
//{
//	[_currentClient setMarkedText:[candidateString string] selectionRange:NSMakeRange(_insertionIndex, 0) replacementRange:NSMakeRange(NSNotFound,NSNotFound)];
//	_insertionIndex = [candidateString length];
//}

- (void)replaceString:(NSString*)string
{
	NSMutableString* str;
	NSInteger strLength = [string length];
	NSInteger replaceStart;
	NSInteger replaceEnd;
	extern ddIM_dict* dict;
	extern IMKCandidates* candidates;
	BOOL stringEnd = false;
	str = [NSMutableString stringWithString:[currentBuffer lastObject]];
	NSLog([@"currentBuffer:" stringByAppendingString:str]);
	NSScanner* scanner = [NSScanner scannerWithString:str];
	NSCharacterSet* lowerCaseCharset = [NSCharacterSet lowercaseLetterCharacterSet];
	if ( [scanner scanUpToCharactersFromSet:lowerCaseCharset intoString:NULL] )
		replaceStart = [scanner scanLocation];
	else
		replaceStart = 0;
	for ( NSInteger i = 0; i<strLength; i++)
	{
		[scanner scanUpToString:@"'" intoString:NULL];
		[scanner scanString:@"'" intoString:NULL];
	}
	if ( [scanner isAtEnd] )
	{
		replaceEnd = [str length] - 1;
		stringEnd = true;
	}
	else
		replaceEnd = [scanner scanLocation] - 1;
	if ( stringEnd )
	{
		[str replaceCharactersInRange:NSMakeRange(replaceStart, replaceEnd - replaceStart + 1) withString:string];
		[self setComposedBuffer:str];
		[candidates setDismissesAutomatically:YES]; //forgot what is going on here
		[self commitComposition:_currentClient];
	}
	else
	{
		[_currentClient setMarkedText:str selectionRange:NSMakeRange(0, [str length]) replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
		NSLog([@"searching:" stringByAppendingString:[str substringFromIndex:(replaceEnd + 1)]]);
		NSLog([self prevBuffer]);
		_candidatesBuffer = [dict searchDict:[str substringFromIndex:(replaceEnd + 1)]:[self prevBuffer]];
		currentPage = 0;
		[self showCandidates];
		[str replaceCharactersInRange:NSMakeRange(replaceStart, replaceEnd - replaceStart + 1) withString:string];
		[_currentClient setMarkedText:str selectionRange:NSMakeRange(0, [str length]) replacementRange:NSMakeRange(NSNotFound, NSNotFound)];
		[currentBuffer addObject:str];
	}
}

- (void)candidateSelected:(NSAttributedString*)candidateString
{
	[self replaceString:[candidateString string]];
}

-(void)autoPinyinPartition
{
	NSMutableString* str;
	if ( [currentBuffer count] > 1 )
	{
		str = [currentBuffer lastObject];
		NSScanner* scanner = [NSScanner scannerWithString:str];
		NSCharacterSet* lowerCaseCharset = [NSCharacterSet lowercaseLetterCharacterSet];
		[scanner scanUpToCharactersFromSet:lowerCaseCharset intoString:NULL];
		//start partition the pinyin from the first lower case char
		NSInteger location = [scanner scanLocation];
		NSInteger length = [str length] - location;
		NSLog([NSString stringWithFormat:@"%d", location]);
		NSLog([NSString stringWithFormat:@"%d", length]);
		for (str in currentBuffer)
			[str replaceCharactersInRange:NSMakeRange([str length] - length, length) withString:[self pinyinPartition:[str substringWithRange:NSMakeRange([str length] - length, length)]]];
	}
	else
		[currentBuffer replaceObjectAtIndex:0 withObject:[self pinyinPartition:[currentBuffer lastObject]]];
}

-(NSMutableString*)pinyinPartition:(NSMutableString*)string
{
//	NSLog(@"start pinyin Partition...");
	extern ddIM_dict* dict;
	NSMutableString* tmp = [NSMutableString stringWithString:string];
	[tmp replaceOccurrencesOfString:@"'" withString:@"" options:NSBackwardsSearch range:NSMakeRange(0, [tmp length])]; //remove all the qrotation make
	NSInteger currentIndex = [tmp length] - 1;
//	NSLog([NSString stringWithFormat:@"%d", currentIndex]);
//	NSLog(tmp);
	NSInteger currentLongest = 0;
	bool candidateFound;
	while ( currentIndex >= 0 )
	{
		candidateFound = false;
		for ( NSString* py in [dict candidatesPY] )
		{
			if ( [[tmp substringWithRange:NSMakeRange(0, currentIndex+1)] hasSuffix:py] )
			{
				if ( [py length] > currentLongest )
				{
					currentLongest = [py length];
					candidateFound = true;
//					NSLog([@"found py candidate: " stringByAppendingString:py]);
				}
			}
		}
		if ( candidateFound )
		{
			[tmp insertString:@"'" atIndex:(currentIndex+1)];
			currentIndex = currentIndex - currentLongest;
			currentLongest = 0;
//			NSLog([NSString stringWithFormat:@"%d", currentIndex]);
		}
		else
			return string;
	}
	NSLog(string);
//	NSLog(@"end pinyin Partition...");
	return tmp;
}

-(NSMenu*)menu
{
	return [[NSApp delegate] menu];
}

-(void)dealloc
{
	[_composedBuffer release];
	[_originalBuffer release];
	[super dealloc];
}

@end
